﻿#region

using System;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using Chapter7_Exercise;

#endregion

namespace Game2048
{
	public partial class Form1 : Form
	{
		private const int N = 4; //方块在纵向及横向上的个数
		private int[,] board; //记录每个方块上的数
		private Button[] btns;

		//用于显示方向按键的窗体
		private frmPad frmpad;
		//最高分记录文件路径
		private string highestScoreFilePath = Application.StartupPath + "\\hs.dat";
		//按钮与窗体边框的距离
		private int margin = 25;
		//此前的最高分
		private int previousHighestScore;

		private int gameMode;
		private int score;
		private string[] str1 = { "夏", "商", "周", "秦", "汉", "隋", "唐", "宋", "元", "明", "清" };
		private string[] str2 = { "一品", "二品", "三品", "四品", "五品", "六品", "七品", "八品", "九品", "良民", "贱民" };
		private string[] str3 = { "士兵", "排长", "连长", "营长", "旅长", "师长", "军长", "司令", "大帅", "良民", "贱民" };

		public Form1()
		{
			InitializeComponent();
			this.Closing += Form1_Closing;
		}

		void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			if (MessageBox.Show("确定退出吗？", "问题", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.Cancel)
			{
				e.Cancel = true;
			}
		}

		//按钮与边框的距离

		private void Form1_Load(object sender, EventArgs e)
		{
			board = new int[N, N];
			score = 0;
			gameMode = 0;

			Text = "Game2048";
			DoubleBuffered = true;

			previousHighestScore = LoadHighestScore();
			ledHighest.Value = previousHighestScore.ToString();

			StartGame();
		}

		private void StartGame()
		{
			//初始化已生成的数字
			board = new int[N, N];
			score = 0;

			//设置两个不同的块为随机的2或4
			Random rnd = new Random();
			int n1 = rnd.Next(N * N);
			int n2;
			do
			{
				n2 = rnd.Next(N * N);
			} while (n1 == n2);
			board[n1 / N, n1 % N] = rnd.Next(2) * 2 + 2; //设为2或4
			board[n2 / N, n2 % N] = rnd.Next(2) * 2 + 2;

			InitialUI();
		}

		//初始化界面
		private void InitialUI()
		{
			//生成按钮
			GenerateAllButtons();
		}


		//产生所有的按钮
		private void GenerateAllButtons()
		{
			pnlBoard.Controls.Clear();

			btns = new Button[N * N];

			//原始代码
			//int x0 = 5, y0 = 5, w = 60, d = w + 5;

			//以下为改进
			//按钮宽度
			int w = 60;


			//按钮之间的距离
			int spacing = (pnlBoard.Width - margin * 2 - w * N) / (N - 1);
			int x0 = margin;
			int y0 = margin;
			int d = w + spacing;


			for (int i = 0; i < btns.Length; i++)
			{
				Button btn = new Button();

				int r = i / N; //行
				int c = i % N; //列

				btn.Left = x0 + c * d;
				btn.Top = y0 + r * d;
				btn.Width = w;
				btn.Height = w;
				btn.Font = new Font("楷体", 16);

				btn.Text = GetTextOfButton(board[r, c]);
				btn.BackColor = GetColorOfButton(board[r, c]);

				btn.Visible = true;
				btns[i] = btn;
				pnlBoard.Controls.Add(btn);
			}
		}

		//更新界面
		private void RefreshUI()
		{
			RefreshAllButtons();
		}

		private void RefreshAllButtons()
		{
			for (int i = 0; i < btns.Length; i++)
			{
				int r = i / N; //行
				int c = i % N; //列
				btns[i].Text = GetTextOfButton(board[r, c]);
				btns[i].BackColor = GetColorOfButton(board[r, c]);
			}
		}

		//得到方块上应有的文字
		private string GetTextOfButton(int n)
		{
			if (n < 2) return "";

			int k = (int)Math.Log(n, 2) - 1;

			if (gameMode == 0)
			{
				return n.ToString();
			}
			if (gameMode == 1)
			{
				return str1[k];
			}
			if (gameMode == 2)
			{
				return str2[k];
			}
			if (gameMode == 3)
			{
				return str3[k];
			}

			return "";
		}

		//得到方块上应有的颜色

		private Color GetColorOfButton(int n)
		{
			if (n == 0) return Color.FromArgb(100, 200, 200, 200);

			int tmp = 230 - (int)Math.Log(n, 2) * 20;
			return Color.FromArgb(250, tmp, tmp, 0);
		}


		/// <summary>
		/// 便于方向按钮窗体调用
		/// </summary>
		/// <param name="keyData"></param>
		public void KeyPressed(Keys keyData)
		{
			Message msg = new Message();
			ProcessCmdKey(ref msg, keyData);
		}

		//处理键盘消息
		//要注意的是:由于按钮等元素的存在,窗体得不到KeyDown事件,所以在覆盖ProcessCmdKey
		protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
		{
			bool bMoved = false;

			if (keyData == Keys.Right)
			{
				bMoved = rightMove();
			}
			else if (keyData == Keys.Left)
			{
				bMoved = leftMove();
			}
			else if (keyData == Keys.Down)
			{
				bMoved = downMove();
			}
			else if (keyData == Keys.Up)
			{
				bMoved = upMove();
			}

			if (bMoved)
			{
				generateNewData();
				RefreshUI();
				ledScore.Value = score.ToString();

				//若当前分数比最高分高，则更改最高分为当前分数
				if (score > Convert.ToInt32(ledHighest.Value))
				{
					ledHighest.Value = score.ToString();
				}


				if (IsGameOver())
				{
					if (score > previousHighestScore)
					{
						MessageBox.Show("游戏结束！恭喜您刷新了最高分！");
						SaveHighestScore(score);
					}
					else
					{
						MessageBox.Show("游戏结束！");
					}
				}

				return true;
			}

			return base.ProcessCmdKey(ref msg, keyData);
		}

		//产生新的随机数据
		private void generateNewData()
		{
			Random rnd = new Random();
			//随机找到一个空的块
			int nCount;
			do
			{
				nCount = rnd.Next(N * N);
			} while (board[nCount / N, nCount % N] != 0);

			board[nCount / N, nCount % N] = rnd.Next(2) * 2 + 2; //其值设为2或者4
		}

		private bool IsGameOver()
		{
			int nCount = 0; //计算非空的格子的个数
			for (int i = 0; i < board.GetLength(0); i++)
			{
				for (int j = 0; j < board.GetLength(1); j++)
				{
					if (board[i, j] > 0) nCount++;
				}
			}
			if (nCount != N * N) return false;

			//如果满了，并且没有可以相邻相同（可合并），则GameOver
			for (int i = 0; i < board.GetLength(0) - 1; i++)
			{
				for (int j = 0; j < board.GetLength(1) - 1; j++)
				{
					if (board[i, j] == 0) continue;
					if (board[i, j] == board[i + 1, j] || board[i, j] == board[i, j + 1])
						return false;
				}
			}
			return true;
		}



		/// <summary>
		///     用于实现游戏模式的单选效果
		/// </summary>
		/// <param name="sender"></param>
		private void SingleCheck(object sender) //自定义函数
		{
			经典CToolStripMenuItem.Checked = false;
			朝代DToolStripMenuItem.Checked = false;
			朝廷PToolStripMenuItem.Checked = false;
			军队AToolStripMenuItem.Checked = false;
			((ToolStripMenuItem)sender).Checked = true;
			RefreshAllButtons();
		}

		private void 经典CToolStripMenuItem_Click(object sender, EventArgs e)
		{
			gameMode = 0;
			SingleCheck(sender);
		}

		private void 朝代DToolStripMenuItem_Click(object sender, EventArgs e)
		{
			gameMode = 1;
			SingleCheck(sender);
		}


		private void 朝廷PToolStripMenuItem_Click(object sender, EventArgs e)
		{
			gameMode = 2;
			SingleCheck(sender);
		}

		private void 军队AToolStripMenuItem_Click(object sender, EventArgs e)
		{
			gameMode = 3;
			SingleCheck(sender);
		}


		/// <summary>
		///     创建最高分记录文件
		/// </summary>
		private void CreateHighestScoreFile()
		{
			int initialSocre = 0;

			try
			{
				FileStream fs = new FileStream(highestScoreFilePath, FileMode.Create);
				BinaryWriter writer = new BinaryWriter(fs);
				writer.Write(initialSocre);
				writer.Close();
			}
			catch (Exception e)
			{
				throw new Exception(e.Message);
			}
		}

		/// <summary>
		///     从文件加载最高分
		/// </summary>
		/// <returns></returns>
		private int LoadHighestScore()
		{
			try
			{
				//若不存在最高分记录文件，则创建一个新的，否则加载最高分
				if (!File.Exists(highestScoreFilePath))
				{
					CreateHighestScoreFile();
				}
				else
				{
					int highestScore;

					FileStream fs = new FileStream(highestScoreFilePath, FileMode.Open);
					BinaryReader reader = new BinaryReader(fs);

					highestScore = reader.ReadInt32();
					reader.Close();
					return highestScore;
				}
			}
			catch (Exception e)
			{
				throw new Exception(e.Message);
			}

			return -1;
		}

		/// <summary>
		///     保存最高分
		/// </summary>
		/// <returns></returns>
		private void SaveHighestScore(int score)
		{
			try
			{
				FileStream fs = new FileStream(highestScoreFilePath, FileMode.Open);
				BinaryWriter writer = new BinaryWriter(fs);

				writer.Write(score);
				writer.Close();
			}
			catch (Exception e)
			{
				throw new Exception(e.Message);
			}
		}



		private void 虚拟按键模式VToolStripMenuItem_Click(object sender, EventArgs e)
		{
			虚拟按键模式VToolStripMenuItem.Checked = !虚拟按键模式VToolStripMenuItem.Checked;

			if (虚拟按键模式VToolStripMenuItem.Checked)
			{
				frmpad = new frmPad(this);
				frmpad.Show();
			}
			else
			{
				frmpad.Close();
			}
		}

		#region 关于四个方向的业务逻辑

		private bool rightMove()
		{
			bool isMoved = false;
			for (int j = 0; j < board.GetLength(0); j++) //针对所有的行
			{
				int x1 = -1, y1 = -1, value1 = -1; // x2=-1, y2=-1,value2=-1;
				for (int i = board.GetLength(1) - 1; i > -1; i--) //从右边起，针对每个块进行处理
				{
					if (board[j, i] == 0) continue; //空的块不处理
					if (board[j, i] == value1) //如果与上一次找到的相等，则合并
					{
						board[x1, y1] = board[x1, y1] * 2;
						board[j, i] = 0;
						value1 = -1;
						score += board[x1, y1];
						isMoved = true;
					}
					else
					{
						int k;
						for (k = i + 1; k < board.GetLength(1); k++) //向右找到一个非空的块
						{
							if (board[j, k] > 0)
								break;
						}
						if (k - 1 != i) //如果这个非空的块左边有空位置
						{
							isMoved = true;
							board[j, k - 1] = board[j, i]; //“移动”到这里（将其上的数字显示到这里）
							board[j, i] = 0;
						}
						value1 = board[j, k - 1]; //记下这个值（非空的块）
						x1 = j;
						y1 = k - 1;
					}
				}
			}
			return isMoved;
		}

		private bool upMove()
		{
			bool isMoved = false;
			for (int i = 0; i < board.GetLength(1); i++)
			{
				int x1 = -1, y1 = -1, value1 = -1; // x2=-1, y2=-1,value2=-1;
				for (int j = 0; j < board.GetLength(0); j++)
				{
					if (board[j, i] != 0)
					{
						if (value1 < 0)
						{
							int k;
							for (k = j - 1; k > -1; k--)
							{
								if (board[k, i] > 0)
									break;
							}
							board[k + 1, i] = board[j, i];
							if (k + 1 != j)
							{
								board[j, i] = 0;
								isMoved = true;
							}
							value1 = board[k + 1, i];
							x1 = k + 1;
							y1 = i;
						}
						else
						{
							if (board[j, i] == value1) //合并
							{
								board[x1, y1] = board[x1, y1] * 2;
								board[j, i] = 0;
								value1 = -1;
								score += board[x1, y1];
								isMoved = true;
							}
							else
							{
								int k;
								for (k = j - 1; k > -1; k--)
								{
									if (board[k, i] > 0)
										break;
								}
								board[k + 1, i] = board[j, i];
								if (k + 1 != j)
								{
									isMoved = true;
									board[j, i] = 0;
								}
								value1 = board[k + 1, i];
								x1 = k + 1;
								y1 = i;
							}
						}
					}
				}
			}
			return isMoved;
		}

		private bool leftMove()
		{
			bool isMoved = false;
			for (int j = 0; j < board.GetLength(0); j++)
			{
				int x1 = -1, y1 = -1, value1 = -1; // x2=-1, y2=-1,value2=-1;
				for (int i = 0; i < board.GetLength(1); i++)
				{
					if (board[j, i] != 0)
					{
						if (value1 < 0)
						{
							int k;
							for (k = i - 1; k > -1; k--)
							{
								if (board[j, k] > 0)
									break;
							}
							board[j, k + 1] = board[j, i];
							if (k + 1 != i)
							{
								isMoved = true;
								board[j, i] = 0;
							}
							value1 = board[j, k + 1];
							x1 = j;
							y1 = k + 1;
						}
						else
						{
							if (board[j, i] == value1) //合并
							{
								board[x1, y1] = board[x1, y1] * 2;
								board[j, i] = 0;
								value1 = -1;
								score += board[x1, y1];
								isMoved = true;
							}
							else
							{
								int k;
								for (k = i - 1; k > -1; k--)
								{
									if (board[j, k] > 0)
										break;
								}
								board[j, k + 1] = board[j, i];
								if (k + 1 != i)
								{
									isMoved = true;
									board[j, i] = 0;
								}
								value1 = board[j, k + 1];
								x1 = j;
								y1 = k + 1;
							}
						}
					}
				}
			}
			return isMoved;
		}


		private bool downMove()
		{
			bool isMoved = false;
			for (int i = 0; i < board.GetLength(1); i++)
			{
				int x1 = -1, y1 = -1, value1 = -1; // x2=-1, y2=-1,value2=-1;
				for (int j = board.GetLength(0) - 1; j > -1; j--)
				{
					if (board[j, i] != 0)
					{
						if (value1 < 0)
						{
							int k;
							for (k = j + 1; k < board.GetLength(0); k++)
							{
								if (board[k, i] > 0)
									break;
							}
							board[k - 1, i] = board[j, i];
							if (k - 1 != j)
							{
								board[j, i] = 0;
								isMoved = true;
							}
							value1 = board[k - 1, i];
							x1 = k - 1;
							y1 = i;
						}
						else
						{
							if (board[j, i] == value1) //合并
							{
								board[x1, y1] = board[x1, y1] * 2;
								board[j, i] = 0;
								value1 = -1;
								score += board[x1, y1];
								isMoved = true;
							}
							else
							{
								int k;
								for (k = j + 1; k < board.GetLength(0); k++)
								{
									if (board[k, i] > 0)
										break;
								}
								board[k - 1, i] = board[j, i];
								if (k - 1 != j)
								{
									board[j, i] = 0;
									isMoved = true;
								}
								value1 = board[k - 1, i];
								x1 = k - 1;
								y1 = i;
							}
						}
					}
				}
			}
			return isMoved;
		}

		#endregion

		private void 退出XToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		private void 重新开始RToolStripMenuItem_Click(object sender, EventArgs e)
		{
			StartGame();

		}
	}
}